package utils

import (
	"fmt"
	"reflect"
)

/*
反射工具
*/
type reflectUtil struct {
}

var reflectInst = &reflectUtil{}

func Reflect() *reflectUtil {
	return reflectInst
}

// Clone 拷贝一个对象
func (r *reflectUtil) Clone(v reflect.Value) reflect.Value {
	switch v.Kind() {
	case reflect.Ptr:
		if v.IsNil() {
			return reflect.Zero(v.Type())
		}
		newPtr := reflect.New(v.Elem().Type())
		newPtr.Elem().Set(r.Clone(v.Elem()))
		return newPtr

	case reflect.Struct:
		newStruct := reflect.New(v.Type()).Elem()
		for i := 0; i < v.NumField(); i++ {
			field := newStruct.Field(i)
			if !field.CanSet() {
				continue
			}
			field.Set(r.Clone(v.Field(i)))
		}
		return newStruct

	case reflect.Slice:
		if v.IsNil() {
			return reflect.Zero(v.Type())
		}
		newSlice := reflect.MakeSlice(v.Type(), v.Len(), v.Cap())
		for i := 0; i < v.Len(); i++ {
			newSlice.Index(i).Set(r.Clone(v.Index(i)))
		}
		return newSlice

	case reflect.Map:
		if v.IsNil() {
			return reflect.Zero(v.Type())
		}
		newMap := reflect.MakeMap(v.Type())
		for _, key := range v.MapKeys() {
			newMap.SetMapIndex(r.Clone(key), r.Clone(v.MapIndex(key)))
		}
		return newMap

	default:
		return v
	}
}

// NewInstanceForType 创建目标对象的实例（如果是指针类型请先解引用）
func (r *reflectUtil) NewInstanceForType(targetType reflect.Type) any {
	// 指针类型需要先解引用
	if targetType.Kind() == reflect.Ptr {
		instance := reflect.New(targetType.Elem()).Interface()
		return instance
	} else { // 一般类型直接实例化
		instance := reflect.New(targetType).Interface()
		return instance
	}
}

// ConvertToType 把一个对象转化为目标类型（产生新的变量）
func (r *reflectUtil) ConvertToType(a any, targetType reflect.Type) (any, error) {
	// 获取原始值
	value := reflect.ValueOf(a)

	// 确保目标类型是指针类型
	if targetType.Kind() != reflect.Ptr {
		return nil, fmt.Errorf("target type must be a pointer")
	}

	// 创建目标类型的实例
	targetValue := reflect.New(targetType.Elem())

	// 如果 a 是指针类型，我们需要解引用它
	if value.Kind() == reflect.Ptr {
		value = value.Elem()
	}

	// 将源值转换为目标类型的值
	if value.Type().AssignableTo(targetType.Elem()) {
		targetValue.Elem().Set(value)
	} else {
		return nil, fmt.Errorf("type conversion not supported")
	}

	// 返回目标类型的值
	return targetValue.Interface(), nil
}

// EachHandler 遍历结构体的处理器，返回false就停止遍历
// f=结构体字段信息 t=字段类型 v=字段值
type EachHandler func(f reflect.StructField, t reflect.Type, value reflect.Value) bool

// EachStruct 遍历一个结构体
func (r *reflectUtil) EachStruct(obj any, handler EachHandler) {
	r.eachStruct(reflect.TypeOf(obj), reflect.ValueOf(obj), handler)
}

// field=结构体字段信息 t=字段类型 v=字段值
func (r *reflectUtil) eachStruct(t reflect.Type, v reflect.Value, handler EachHandler) {
	if t.Kind() == reflect.Ptr { // 如果是指针就解引用
		if v.IsNil() {
			// logx.Debugf("eachStruct fot nil")
			return
		}
		t = t.Elem()
		v = v.Elem()
	}
	// 不是结构体
	if t.Kind() != reflect.Struct {
		panic(fmt.Errorf("type %s is not a struct", t.String()))
	}
	// 遍历结构体字段
	for i := 0; i < t.NumField(); i++ {
		field := t.Field(i)
		value := v.Field(i)
		// 如果是匿名字段（嵌入结构体）
		if field.Anonymous && field.Type.Kind() == reflect.Struct {
			r.eachStruct(field.Type, value, handler) //　递归解析
		} else if value.IsValid() && field.PkgPath == "" {
			if !handler(field, field.Type, value) { // 处理器返回false，不再继续处理
				return
			}
		}
	}
}

// GetFiledValue 通过反射获取任意对象的指定字段值
func (r *reflectUtil) GetFiledValue(obj any, fieldName string) (any, error) {
	// 获取对象的反射值
	val := reflect.ValueOf(obj)
	// 如果是指针，获取其指向的值
	if val.Kind() == reflect.Ptr {
		val = val.Elem()
	}
	// 确保是结构体类型
	if val.Kind() != reflect.Struct {
		return nil, fmt.Errorf("obj should be a struct, but got %v", val.Kind())
	}
	// 获取字段
	field := val.FieldByName(fieldName)
	if !field.IsValid() {
		return nil, fmt.Errorf("field %s not found", fieldName)
	}
	return field.Interface(), nil
}
